package org.common.utils.fasttest;

import com.esotericsoftware.reflectasm.MethodAccess;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * @author zhouzhibing
 * @date 2024/11/21
 */
public class TestReflectAsm {

    public static void test() {
        MyEntity myEntity = new MyEntity();

        int count = 100000000;

        Map<Class<?> , MyMethodAccess> methodAccessMap = new HashMap<>();
        methodAccessMap.put(MyEntity.class , new MyMethodAccess(MethodAccess.get(MyEntity.class)));

        Map<Class<?> , MyMethod> methodMap = new HashMap<>();
        methodMap.put(MyEntity.class , new MyMethod(MyEntity.class));


//        Test.doHandler("MethodAccess" , count , 10 , (index) -> {
//            MethodAccess methodAccess = MethodAccess.get(MyEntity.class);
//            Object invoker = methodAccess.invoke(myEntity, "getName");
//        });

        Test.doHandler("MyMethodAccess" , count , 10 , (index) -> {
            MyMethodAccess myMethodAccess = methodAccessMap.get(MyEntity.class);
            Object invoker = myMethodAccess.invoker(myEntity, "getName");
        });

//        Test.doHandler("method" , count , 10 , (index) -> {
//            MyMethod myMethod = methodMap.get(MyEntity.class);
//            Object invoker = myMethod.invoker(myEntity, "getName");
//        });

//        String methodName = "getName";
//        Test.doHandler("dic" , count , 10 , (index) -> {
//            switch (methodName) {
//                case "getName" -> {
//                    Object name = myEntity.getName();
//                }
//                case "setName" -> {
//                    myEntity.setName("");
//                }
//                case "setName1" -> {
//                    myEntity.setName("");
//                }
//                case "setName2" -> {
//                    myEntity.setName("");
//                }
//                case "setName3" -> {
//                    myEntity.setName("");
//                }
//                case "setName4" -> {
//                    myEntity.setName("");
//                }
//            }
//        });

    }

    public static class MyInvoke {
        public <T> T  invoker(Object instance , String methodName ,Object ...params) {
            MyEntity myEntity = (MyEntity)instance;
            return switch (methodName) {
                case "getName" -> { yield (T)myEntity.getName(); }
                case "setName" -> { yield (T)myEntity.getName(); }
                case "getAge" -> { yield (T)myEntity.getName(); }
                case "setAge" -> { yield (T)myEntity.getName(); }
                default -> throw new IllegalStateException("Unexpected value: " + methodName);
            };
        }
    }

    public static class MyMethod {
        private Map<String, Method> methodMap;

        MyMethod(Class<?> clzss) {
            methodMap = new HashMap<>();
            for (Method method : clzss.getMethods()) {
                methodMap.put(method.getName() , method);
            }
        }

        public <T> T  invoker(Object instance , String methodName ,Object ...params) {
            Method method = methodMap.get(methodName);
            try {
                return (T)method.invoke(instance , params);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
    public static class MyMethodAccess {
        private MethodAccess methodAccess;

        private Map<String , Integer> methodIndexMap;

        MyMethodAccess(MethodAccess methodAccess) {
            this.methodAccess = methodAccess;
            this.methodIndexMap = new HashMap<>();
            String[] methodNames = methodAccess.getMethodNames();
            for (int i = 0; i < methodNames.length; i++) {
                String methodName = methodNames[i];
                methodIndexMap.put(methodName , i);
            }
        }

        public <T> T  invoker(Object instance , String methodName ,Object ...params) {
            Integer index = methodIndexMap.get(methodName);
            return (T)methodAccess.invoke(instance, index, params);
        }
    }

    public static class MyEntity {
        private String name = "MyEntity";

        private int age;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }
    }
}

